
#include <base/engine.h>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))

#define GET_WIDTH(lp)  ((int)(short)LOWORD(lp))
#define GET_HEIGHT(lp) ((int)(short)HIWORD(lp))

#define APP_TITLE "Editor"

#include "resource.h"
#include "controller.h"
#include "application.h"

#include <string>

char filename[256];
OPENFILENAME open_file;
float scale = 1.0;
float x = 0.0;
float y = 0.0;

int xPos = 0, yPos = 0;
float xPosf = 0.0;
float yPosf = 0.0;

// EntryMessageHandler /////////////////////////////////////////
//   Handles windows events
LRESULT WINAPI EntryMessageHandler(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);

// WinMain /////////////////////////////////////////////////////
//   The big kahuna
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT){

  HWND m_hWnd; //the window handle

  //create the window
  WNDCLASSEX WindowClass = {sizeof(WNDCLASSEX), CS_CLASSDC, EntryMessageHandler, 0, 0, GetModuleHandle(NULL), NULL, NULL, NULL, MAKEINTRESOURCE(IDR_MENU1), "Host Application", NULL};
	RegisterClassEx(&WindowClass);
	m_hWnd = CreateWindowEx(0, "Host Application", APP_TITLE, WS_OVERLAPPEDWINDOW | WS_HSCROLL  | WS_VSCROLL , CW_USEDEFAULT, 0, 650, 650, GetDesktopWindow(), NULL, WindowClass.hInstance, NULL);
  if(m_hWnd)
		ShowWindow(m_hWnd, SW_SHOW);
	else
		return 0;

  InitializeEngine(m_hWnd, m_hWnd, RunApplication);

  PrintConsoleLine("Starting message pump");
	MSG Message;
  memset(&Message,0,sizeof(Message));

  while(Message.message != WM_QUIT)
	{
    if(PeekMessage(&Message, 0, 0, 0, PM_REMOVE)){
      TranslateMessage(&Message);
		  DispatchMessage(&Message);
    }else{
      IterateEngine();
    }
  }

  DestroyEngine();

	return 0;
}

// EntryMessageHandler /////////////////////////////////////////
//   Handles windows events
LRESULT WINAPI EntryMessageHandler(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam){
  PAINTSTRUCT ps;
  HDC hdc;
  HMENU menu;
  UINT state;

	switch(Message)
	{
    case WM_CREATE:
      open_file.lStructSize = sizeof(OPENFILENAME);
      open_file.hwndOwner = hWnd;
      open_file.lpstrFilter = "All Files\0*.*\0\0";
      open_file.lpstrCustomFilter = NULL;
      open_file.nFilterIndex = NULL;
      open_file.lpstrFile = filename;
      filename[0] = '\0';
      open_file.nMaxFile = 256;
      open_file.lpstrFileTitle = NULL;
      open_file.lpstrInitialDir = NULL;
      open_file.lpstrTitle = NULL;
      open_file.Flags = OFN_FILEMUSTEXIST | OFN_OVERWRITEPROMPT;
      open_file.lpstrDefExt = NULL;
      break;

    case WM_PAINT:
      hdc = BeginPaint(hWnd,&ps);
      EndPaint(hWnd,&ps);
      break;

    case WM_COMMAND:
      switch(wParam){
        case IDCANCEL:
        case ID_FILE_EXIT:
          PostQuitMessage(0);
          break;
        case ID_FILE_NEWFILE:
          events::Fire(new StageFileEvent(STAGE_NEW, ""));
          break;
        case ID_FILE_OPENFILE:
          if(GetOpenFileName(&open_file))
            events::Fire(new StageFileEvent(STAGE_LOAD, filename));
          break;
        case ID_FILE_SAVEFILE:
          if(filename[0] == '\0'){
            if(GetSaveFileName(&open_file))
              events::Fire(new StageFileEvent(STAGE_SAVE, filename));
          }else{
            events::Fire(new StageFileEvent(STAGE_SAVE, filename));
          }
          break;
        case ID_FILE_SAVEAS:
          if(GetSaveFileName(&open_file))
            events::Fire(new StageFileEvent(STAGE_SAVE, filename));
          break;
        case ID_ENGINE_CONSOLE:
          menu = GetMenu(hWnd);
          state = GetMenuState(menu, ID_ENGINE_CONSOLE, MF_BYCOMMAND);  
          SetConsoleVisible(!(state & MF_CHECKED));
          CheckMenuItem(menu, ID_ENGINE_CONSOLE, MF_BYCOMMAND | (~state & MF_CHECKED));
          break;
        case ID_VIEW_GRID: 
          menu = GetMenu(hWnd);
          state = GetMenuState(menu, ID_VIEW_GRID, MF_BYCOMMAND); 
          CheckMenuItem(menu, ID_VIEW_GRID, MF_BYCOMMAND | (~state & MF_CHECKED));
          events::Fire(new AppOptionEvent(OPTION_GRID, !state));
          break;
      }
      break;

    case WM_MOUSEMOVE:
      if(GetDevice(0)){
        xPos = GET_X_LPARAM(lParam); 
        yPos = GET_Y_LPARAM(lParam);
        xPosf = (2.0 * xPos / GetDevice(0)->deviceWidth()) - 1;
        yPosf = 1 - (2.0 * yPos / GetDevice(0)->deviceHeight());
        events::Fire(new MouseEvent(xPosf, yPosf, 0));
      }
      break;

    case WM_LBUTTONDOWN:
      events::Fire(new MouseEvent(xPosf, yPosf, MOUSE_LEFT | MOUSE_DOWN));
      break;

    case WM_LBUTTONUP:
      events::Fire(new MouseEvent(xPosf, yPosf, MOUSE_LEFT | MOUSE_UP));
      break;

    case WM_RBUTTONDOWN:
      events::Fire(new MouseEvent(xPosf, yPosf, MOUSE_RIGHT | MOUSE_DOWN));
      break;

    case WM_RBUTTONUP:
      events::Fire(new MouseEvent(xPosf, yPosf, MOUSE_RIGHT | MOUSE_UP));
      break;

    case WM_SIZE:
      if(GetDevice(0))
        GetDevice(0)->reset(GET_WIDTH(lParam), GET_HEIGHT(lParam));
      events::Fire(new ViewEvent(x, y, GET_WIDTH(lParam), GET_HEIGHT(lParam), scale));
      break;

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
	}

	return DefWindowProc(hWnd, Message, wParam, lParam);
}

